#include <iostream>
#include <vector>
using namespace std;

const int INF = 0x3f3f3f3f; // 定义一个极大值表示无穷大

int main() {
    int n;
    cin >> n;
    int deadline[30];   // 存储每个任务的截止时间
    int cost[30];       // 存储每个任务的耗时
    int MAXN = 1 << n;  // 总状态数（2^n种组合）
    int sum = 0;        // 临时变量，用于计算总耗时
    
    // 输入任务数据
    for (int i = 0; i < n; i++) {
        cin >> deadline[i] >> cost[i];
    }
    
    // 初始化动态规划数组，dp[mask]表示选中mask对应任务时的最小总超时
    vector<int> dp(MAXN, INF); // 初始化为无穷大
    dp[0] = 0; // 初始状态：未选任何任务，超时为0
    
    // 遍历所有可能的状态（0 到 2^n-1）
    for (int i = 0; i < MAXN; i++) {
        // 遍历每个任务，检查是否可以被加入当前状态
        for (int j = 0; j < n; j++) {
            // 若当前状态i未选中任务j（即第j位为0）
            if (!(i & (1 << j))) {
                int next = i | (1 << j); // 新状态：选中任务j后的掩码
                
                // 计算已选任务的总耗时（遍历所有已选任务）
                int time = 0;
                for (int k = 0; k < n; k++) {
                    if ((1 << k) & i) { // 若任务k已被选中
                        time += cost[k];
                    }
                }
                
                // 计算新增任务j的超时增量（若超时则为正，否则为0）
                int add = max(0, time + cost[j] - deadline[j]);
                
                // 更新新状态的最小超时（取当前值与转移值的较小者）
                dp[next] = min(dp[next], dp[i] + add);
            }
        }
    }
    
    // 输出结果：所有任务都被选中时的最小总超时
    cout << dp[MAXN - 1] << endl;
    return 0;
}